package com.simple.util.base.extend.video;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: simple_tools
 * @description: 视频操作工具类
 * @author: ChenWenLong
 * @create: 2020-01-07 09:19
 **/
public class VideoUtil {

    private String ffmpegPath = "D:\\Program Files\\ffmpeg-20180227-fa0c9d6-win64-static\\bin\\ffmpeg.exe";//ffmpeg的安装位置
    private String videoPath = "D:\\BaiduNetdiskDownload\\test1.avi";
    private String m3u8Name = "test1.m3u8";
    private String m3u8folderPath = "D:/BaiduNetdiskDownload/Movies/test1/";

    public VideoUtil(String ffmpegPath) {
        this.ffmpegPath = ffmpegPath;
        this.videoPath = videoPath;
        this.m3u8Name = m3u8Name;
        this.m3u8folderPath = m3u8folderPath;
    }

    /**
     * 功能描述:
     * 〈检查视频时间是否一致〉
     *
     * @return : java.lang.Boolean
     * @params : [source, target]
     * @author : cwl
     * @date : 2020/1/7 9:22
     */
    public Boolean checkVideoTime(String source, String target) {
        String sourceTime = getVideoTime(source);
        //取出时分秒
        sourceTime = sourceTime.substring(0, sourceTime.lastIndexOf("."));
        String targetTime = getVideoTime(target);
        //取出时分秒
        targetTime = targetTime.substring(0, targetTime.lastIndexOf("."));
        if (sourceTime == null || targetTime == null) {
            return false;
        }
        if (sourceTime.equals(targetTime)) {
            return true;
        }
        return false;
    }

    /**
     * 功能描述:
     * 〈获取视频时间(时：分：秒：毫秒)〉
     *
     * @return : java.lang.String
     * @params : [video_path]
     * @author : cwl
     * @date : 2020/1/7 9:22
     */
    public String getVideoTime(String videoPath) {
        /*
        ffmpeg -i  lucene.mp4
         */
        List<String> commend = new ArrayList<String>();
        commend.add(ffmpegPath);
        commend.add("-i");
        commend.add(videoPath);
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commend);
            //将标准输入流和错误输入流合并，通过标准输入流程读取信息
            builder.redirectErrorStream(true);
            Process p = builder.start();
            String outstring = waitFor(p);
            System.out.println(outstring);
            int start = outstring.trim().indexOf("Duration: ");
            if (start >= 0) {
                int end = outstring.trim().indexOf(", start:");
                if (end >= 0) {
                    String time = outstring.substring(start + 10, end);
                    if (time != null && !time.equals("")) {
                        return time.trim();
                    }
                }
            }

        } catch (Exception ex) {

            ex.printStackTrace();

        }
        return null;
    }

    public String waitFor(Process p) {
        InputStream in = null;
        InputStream error = null;
        String result = "error";
        int exitValue = -1;
        StringBuffer outputString = new StringBuffer();
        try {
            in = p.getInputStream();
            error = p.getErrorStream();
            boolean finished = false;
            int maxRetry = 600;//每次休眠1秒，最长执行时间10分种
            int retry = 0;
            while (!finished) {
                if (retry > maxRetry) {
                    return "error";
                }
                try {
                    while (in.available() > 0) {
                        Character c = new Character((char) in.read());
                        outputString.append(c);
                        System.out.print(c);
                    }
                    while (error.available() > 0) {
                        Character c = new Character((char) in.read());
                        outputString.append(c);
                        System.out.print(c);
                    }
                    //进程未结束时调用exitValue将抛出异常
                    exitValue = p.exitValue();
                    finished = true;

                } catch (IllegalThreadStateException e) {
                    Thread.currentThread().sleep(1000);//休眠1秒
                    retry++;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
        return outputString.toString();

    }

    private void clearM3u8(String m3u8Path) {
        //删除原来已经生成的m3u8及ts文件
        File m3u8dir = new File(m3u8Path);
        if (!m3u8dir.exists()) {
            m3u8dir.mkdirs();
        }
       /* if(m3u8dir.exists()&&m3u8_path.indexOf("/hls/")>=0){//在hls目录方可删除，以免错误删除
            String[] children = m3u8dir.list();
            //删除目录中的文件
            for (int i = 0; i < children.length; i++) {
                File file = new File(m3u8_path, children[i]);
                file.delete();
            }
        }else{
            m3u8dir.mkdirs();
        }*/
    }

    /**
     * 功能描述:
     * 〈生成m3u8文件〉
     *  成功则返回success，失败返回控制台日志
     *
     * @params : []
     * @return : java.lang.String
     * @author : cwl
     * @date : 2020/1/7 9:23
     */
    public String generateM3u8() {
        //清理m3u8文件目录
        clearM3u8(m3u8folderPath);
 /*
        ffmpeg -i  lucene.mp4   -hls_time 10 -hls_list_size 0   -hls_segment_filename ./hls/lucene_%05d.ts ./hls/lucene.m3u8
         */
//        String m3u8_name = video_name.substring(0, video_name.lastIndexOf("."))+".m3u8";
        List<String> commend = new ArrayList<String>();
        commend.add(ffmpegPath);
        commend.add("-i");
        commend.add(videoPath);
        commend.add("-hls_time");
        commend.add("10");
        commend.add("-hls_list_size");
        commend.add("0");
        commend.add("-hls_segment_filename");
//        commend.add("D:/BaiduNetdiskDownload/Movies/test1/test1_%05d.ts");
        commend.add(m3u8folderPath + m3u8Name.substring(0, m3u8Name.lastIndexOf(".")) + "_%05d.ts");
//        commend.add("D:/BaiduNetdiskDownload/Movies/test1/test1.m3u8");
        commend.add(m3u8folderPath + m3u8Name);
        String outstring = null;
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commend);
            //将标准输入流和错误输入流合并，通过标准输入流程读取信息
            builder.redirectErrorStream(true);
            Process p = builder.start();
            outstring = waitFor(p);

        } catch (Exception ex) {

            ex.printStackTrace();

        }
        //通过查看视频时长判断是否成功
        Boolean checkVideoTime = checkVideoTime(videoPath, m3u8folderPath + m3u8Name);
        if (!checkVideoTime) {
            return outstring;
        }
        //通过查看m3u8列表判断是否成功
        List<String> tsList = getTsList();
        if (tsList == null) {
            return outstring;
        }
        return "success";


    }

    /**
     * 功能描述:
     * 〈检查视频处理是否完成〉
     *
     * @return : java.util.List<java.lang.String>
     * @params : []
     * @author : cwl
     * @date : 2020/1/7 9:23
     */
    public List<String> getTsList() {
        // String m3u8_name = video_name.substring(0, video_name.lastIndexOf("."))+".m3u8";
        List<String> fileList = new ArrayList<String>();
        List<String> tsList = new ArrayList<String>();
        String m3u8file_path = m3u8folderPath + m3u8Name;
        BufferedReader br = null;
        String str = null;
        String bottomline = "";
        try {
            br = new BufferedReader(new FileReader(m3u8file_path));
            while ((str = br.readLine()) != null) {
                bottomline = str;
                if (bottomline.endsWith(".ts")) {
                    tsList.add(bottomline);
                }
                //System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if (bottomline.contains("#EXT-X-ENDLIST")) {
//            fileList.add(hls_relativepath+m3u8_name);
            fileList.addAll(tsList);
            return fileList;
        }
        return null;

    }
}
